package com.cans.lightning.business.lowcode.service.impl;

import com.cans.lightning.business.lowcode.dto.AppTableDto;
import com.cans.lightning.business.lowcode.dto.AppTableFieldDto;
import com.cans.lightning.business.lowcode.enums.FieldTypeEnum;
import com.cans.lightning.business.lowcode.service.api.IDBTableDoOperatorService;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.tuple.Pair;
import org.beetl.sql.core.SQLManager;
import org.beetl.sql.core.SQLReady;
import org.beetl.sql.core.db.DBType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 数据库表操作Service
 *
 * @author cans
 * @date 2022/11/6
 **/
@Service
public class MySqlDBTableOperatorServiceImpl implements IDBTableDoOperatorService {

    private static final Logger logger = LoggerFactory.getLogger(MySqlDBTableOperatorServiceImpl.class);

    @Resource
    private SQLManager sqlManager;

    /**
     * 创建数据库表
     *
     * @param tableDto 表信息
     */
    @Override
    public void createTable(AppTableDto tableDto) {
        String dbTableName = tableDto.getDbTableName();
        sqlManager.getMetaDataManager().refresh();
        boolean existTable = sqlManager.getMetaDataManager().existTable(dbTableName);
        if (existTable) {
            logger.info("表[" + dbTableName + "]已存在");
            return;
        }

        StringBuilder sqlBuilder = new StringBuilder();
        sqlBuilder.append("CREATE TABLE ").append(dbTableName).append(" ( ");
        sqlBuilder.append("  `id` varchar(36) COLLATE utf8mb4_bin NOT NULL, ");

        List<AppTableFieldDto> fieldArr = tableDto.getFieldArr().stream().filter(item -> item.getId() != null && !item.getDelete()).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(fieldArr)) {
            for (AppTableFieldDto fieldDto : fieldArr) {
                sqlBuilder.append(this.getAppendFieldSql(fieldDto));
                sqlBuilder.append(" COLLATE utf8mb4_bin DEFAULT NULL, ");
            }
        }
        sqlBuilder.append("  `create_time` datetime NOT NULL, ").append("  `last_change_time` datetime NOT NULL, ");
        sqlBuilder.append("  PRIMARY KEY (`id`) USING BTREE " +
                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;");

        sqlManager.executeUpdate(sqlBuilder.toString(), Maps.newHashMap());
    }

    @Override
    public void createField(AppTableDto tableDto, AppTableFieldDto fieldDto) {
        String sqlBuilder = "ALTER TABLE " + tableDto.getDbTableName() + " ADD COLUMN " +
                this.getAppendFieldSql(fieldDto)
                + " DEFAULT NULL COMMENT '" + fieldDto.getFieldName() + "' ";
        sqlManager.executeUpdate(sqlBuilder, Maps.newHashMap());
    }

    @Override
    public void ifNotExitCreate(AppTableDto appTableDto, AppTableFieldDto fieldDto) {
        SQLReady sqlReady = new SQLReady("SELECT count(1) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='" + appTableDto.getTableName() + "' AND COLUMN_NAME='" + fieldDto.getDbFieldName() + "';");
        Integer integer = sqlManager.executeQueryOne(sqlReady, Integer.class);
        if (integer == null || integer == 0) {
            this.createField(appTableDto, fieldDto);
        }
    }

    @Override
    public int getDbType() {
        return DBType.DB_MYSQL;
    }

    private String getAppendFieldSql(AppTableFieldDto fieldDto) {
        StringBuilder sqlBuilder = new StringBuilder();
        Pair<String, Integer> fieldType = this.getFieldType(fieldDto);
        String dbType = fieldType.getLeft();
        Integer length = fieldType.getRight();
        sqlBuilder.append("  `").append(fieldDto.getDbFieldName()).append("` ").append(dbType);
        if (length != null) {
            sqlBuilder.append("(").append(length).append(")");
        }
        return sqlBuilder.toString();
    }

    private Pair<String, Integer> getFieldType(AppTableFieldDto fieldDto) {
        FieldTypeEnum typeEnum = FieldTypeEnum.getByKey(fieldDto.getDbFieldDataType());
        if (typeEnum == null) {
            throw new RuntimeException("不支持的字段类型: " + fieldDto.getDbFieldDataType());
        }
        String dbType = "";
        Integer length = fieldDto.getLength();
        switch (typeEnum) {
            case VARCHAR:
                dbType = "varchar";
                length = length == null ? 200 : length;
                break;
            case INT:
                dbType = "int";
                break;
            case DATE:
                dbType = "date";
                length = null;
                break;
            case FILE:
                dbType = "varchar";
                length = 36;
                break;
            case DECIMAL:
                dbType = "decimal";
                break;
            case DATE_TIME:
                dbType = "datetime";
                length = null;
                break;
        }
        return Pair.of(dbType, length);
    }
}
